module scene.selectserver;

import std.string;

import scene.scene;
import mirdefine, mirshare, mirgame, mirsound;
import common.imagearray;

import share.container, share.edcode, share.nettcp, share.protocol, share.types, share.utility;

import allegro5.allegro;
import allegro5.allegro_primitives;
import allegro5.allegro_font;


const POS_SERVERLIST_BORDER_X       = 50;
const POS_SERVERLIST_BORDER_Y       = 0;
const SERVERLIST_BORDER_WIDTH       = 151;

const POS_TOP_SERVER_BTN_X          = 0;
const POS_TOP_SERVER_BTN_Y          = 10;

const SERVER_BTN_WIDTH              = 100;
const SERVER_BTN_HEIGHT             = 20;
const SERVER_BTN_GAP                = 10;
const COUNT_BUTTON_PER_COLUMN       = 8;

const SERVER_LIST_BKCOLOR           = ALLEGRO_COLOR(125/255.0f, 125/255.0f, 125/255.0f, 125/255.0f);

const SERVER_BTN_TEXTCOLOR_NORMAL   = ALLEGRO_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
const SERVER_BTN_TEXTCOLOR_FOCUS    = ALLEGRO_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
const SERVER_BTN_TEXTCOLOR_CLICK    = ALLEGRO_COLOR(0.0f, 0.2f, 1.0f, 1.0f);

const SERVER_BTN_BKCOLOR_NORMAL     = ALLEGRO_COLOR(125/255.0f, 125/255.0f, 125/255.0f, 125/255.0f);
const SERVER_BTN_BKCOLOR_FOCUS      = ALLEGRO_COLOR(95/255.0f, 95/255.0f, 95/255.0f, 125/255.0f);
const SERVER_BTN_BKCOLOR_CLICK      = ALLEGRO_COLOR(125/255.0f, 125/255.0f, 0, 125/255.0f);

const _LEFT_BORDER                  = 20;
const _TOP_BORDER                   = 60;
const _RIGHT_BORDER                 = 120;
const _BOTTOM_BORDER                = 310;


struct ServerButton
{
    public IntRectangle region;
    public string caption;
    public string name;
    public int count;
    public ALLEGRO_COLOR text_color;
    public ALLEGRO_COLOR back_color;
    public bool selected;
}

struct ServerInfo
{
    public string caption;
    public string name;
    public int count;
}

public class GameSelectServerScene : Scene
{
    private IntRectangle _region;
    private bool _is_active;
    
    private bool _is_button_down;

    private ImageArray _iarray;
    
    private Vector!(ServerInfo) _servers;

    private ServerButton[] _server_btn;
    private int _server_count;
    private bool _is_selected;
    
    public this(Game game)
    {
        super(game, SceneType.SelectServer);
        
        _region = IntRectangle.zero;
        _is_active = false;
        
        _is_button_down = false;

        _iarray = new ImageArray;
        _iarray.FileName = "./Data/LoginInterface.wil";
        _iarray.LibType = LibraryType.UseCache;
        _iarray.IVersion = InternationalVersion.English;

        _servers = _servers.init;
        _server_btn = null;
        _server_count = 0;
        _is_selected = false;
    }

    public override void Initialize()
    {
        bool readok = ReadServerList();

        _iarray.initialize();

        int nTop, nLeft;
        
        // Buttons
        _server_count = _servers.count();
        _server_btn = new ServerButton[_server_count];
        _is_selected = false;
        
        int idx = 0;
        for (int i = 0; i <= ((_server_count - 1) / COUNT_BUTTON_PER_COLUMN); i++)
        {
            for (int j = i * COUNT_BUTTON_PER_COLUMN; (j < _server_count && j < (COUNT_BUTTON_PER_COLUMN * (i + 1))); j++)
            {
                if (idx >= _servers.count()) break;
                auto info = _servers[idx];
                
                _server_btn[j] = ServerButton.init;
                _server_btn[j].name = info.name;
                _server_btn[j].caption = info.caption;
                _server_btn[j].count = info.count;
                _server_btn[j].text_color = SERVER_BTN_TEXTCOLOR_NORMAL;
                _server_btn[j].back_color = SERVER_BTN_BKCOLOR_NORMAL;
                _server_btn[j].selected = false;
                
                nLeft = POS_TOP_SERVER_BTN_X + i * SERVER_BTN_WIDTH;
                nTop  = POS_TOP_SERVER_BTN_Y + (j - i * COUNT_BUTTON_PER_COLUMN) * (SERVER_BTN_HEIGHT+SERVER_BTN_GAP);
                _server_btn[j].region.set(nLeft, nTop, nLeft + SERVER_BTN_WIDTH, nTop + SERVER_BTN_HEIGHT);
                idx++;
            } 
        }
        
        
        int left, top, right, bottom;
        
        left = _LEFT_BORDER;
        top = _TOP_BORDER;
        
        if (((_server_count - 1) / COUNT_BUTTON_PER_COLUMN) > 0)
            right = _LEFT_BORDER + SERVER_BTN_WIDTH * (((_server_count - 1) / COUNT_BUTTON_PER_COLUMN) + 1);
        else
            right = _LEFT_BORDER + SERVER_BTN_WIDTH;
        
        if (((_server_count - 1) / COUNT_BUTTON_PER_COLUMN) > 0)
            bottom = _TOP_BORDER + POS_TOP_SERVER_BTN_Y + (COUNT_BUTTON_PER_COLUMN) * (SERVER_BTN_HEIGHT + SERVER_BTN_GAP);
        else
            bottom = _BOTTOM_BORDER;
        
        _region.set(left, top, right, bottom);
        
        MySocket.setHandler(&parsing);
    }

    public override void Finalize()
    {
        _server_count = 0;
        _server_btn = null;
        
        _servers.clear();
        
        _iarray.finalize();
    }
    
    private bool ReadServerList()
    {
        // PDS: hacked const cast away for now.
        static const char* flname = "./Mir3.ini";
        static const char* server_section = "Server";
        char* ptr;
        string fmt, value;
        
        
        auto config = al_load_config_file(flname);
        if (config is null) return false;
        
        ptr = cast(char*)al_get_config_value(config, server_section, "ServerCount");
        value = std.conv.to!string(ptr);
        
        _server_count = std.conv.to!int(value);
        _server_count = std.algorithm.min(_server_count, 30);
        
        _servers.clear();
        for (int i = 0; i < _server_count; i++)
        {
            ServerInfo info;
            
            fmt = format("server%scaption", (i + 1));
            ptr = cast(char*)al_get_config_value(config, server_section, fmt.toStringz);
            info.caption = std.conv.to!string(ptr);
            
            fmt = format("server%sname", (i + 1));
            ptr = cast(char*)al_get_config_value(config, server_section, fmt.toStringz);
            info.name = std.conv.to!string(ptr);
            
            _servers.add(info);
        }
        
        al_destroy_config(config);
        
        return true;
    }

    public void DecodeServerList(string data)
    {
        /+ServerInfo info;
        string sdata, sname, scount;


        _servers.clear();
        auto bodyy = DecodeString(data);
        while (bodyy.length > 0)
        {
            bodyy = GetValidStr3(bodyy, sdata, [';']);

            if (sdata.length > 0)
            {
                info.caption = sdata;
                info.name = sdata;
                info.count = 0;
                _servers.add(info);
            }
            else
                break;
            /*auto n = sdata.indexOf('(');
            if (n > 0)
            {
                sname = sdata[0 .. n];
                if (sname.length > 0)
                {
                    ArrestStringEx(sdata, '(', ')', scount);
                    if (scount != "")
                    {
                        info.caption = sname;
                        info.name = sname;
                        info.count = std.conv.to!int(scount);
                        _servers.add(info);
                    }
                }
            }
            else
                break;*/
        }+/
    }
    
    private void GetSelectionRect(ref IntRectangle rc, in ServerButton btn)
    {
        rc.set(_region.getLeft() + btn.region.getLeft(),
               _region.getTop() + btn.region.getTop(),
               _region.getLeft() + btn.region.getRight(),
               _region.getTop() + btn.region.getBottom());
    }
    
    
    public override void MouseDown(uint button, in IntPoint pt)
    {
        if (button != 1) return;

        if (_is_selected) return;

        IntRectangle rc;
        _is_button_down = true;
        
        for (int i = 0; i < _server_count; i++)
        {
            GetSelectionRect(rc, _server_btn[i]);
            
            if (rc.pointInside(pt))
            {
                _server_btn[i].text_color = SERVER_BTN_TEXTCOLOR_CLICK;    // COLOR(BLACK)
                _server_btn[i].back_color = SERVER_BTN_BKCOLOR_CLICK;
                _server_btn[i].selected = true;
            }
        }
    }
    
    public override void MouseUp(uint button, in IntPoint pt)
    {
        if (button != 1) return;

        if (_is_selected) return;

        IntRectangle rc;
        _is_button_down = false;
        
        for (int i = 0; i < _server_count; i++)
        {
            GetSelectionRect(rc, _server_btn[i]);
            
            if (rc.pointInside(pt))
            {
                MySocket.SendSelectServer(_server_btn[i].name);
                _is_selected = true;
            }
            _server_btn[i].text_color = SERVER_BTN_TEXTCOLOR_NORMAL;            // COLOR(YELLOW)
            _server_btn[i].back_color = SERVER_BTN_BKCOLOR_NORMAL;
            _server_btn[i].selected = false;
        }
    }
    
    public override void MouseMove(in IntPoint pt)
    {
        IntRectangle rc;

        if (_is_selected) return;

        if (!_is_button_down)
        {
            for (int i = 0; i < _server_count; i++)
            {
                GetSelectionRect(rc, _server_btn[i]);
                
                if (rc.pointInside(pt))
                {
                    _server_btn[i].text_color = SERVER_BTN_TEXTCOLOR_FOCUS;         // COLOR(YELLOW)
                    _server_btn[i].back_color = SERVER_BTN_BKCOLOR_FOCUS;
                    _server_btn[i].selected = true;
                }
                else
                {
                    _server_btn[i].text_color = SERVER_BTN_TEXTCOLOR_NORMAL;        // COLOR(WHITE)
                    _server_btn[i].back_color = SERVER_BTN_BKCOLOR_NORMAL;
                    _server_btn[i].selected = false;
                }
            }
        }
    }
    
    public override void OpenScene()
    {
        _is_active = true;
    }
    
    public override void CloseScene()
    {
        _is_active = false;
    }
    
    public override void PlayScene()
    {
        const clear_color = al_map_rgba_f(0.0, 0.0, 0.0, 0.0);
        ALLEGRO_COLOR color;
        ALLEGRO_BITMAP* bmp;
        IntRectangle rc;

        al_clear_to_color(clear_color);
        
        if (!_is_active) return;
        
        // draw background picture
        bmp = _iarray[0];
        if (bmp !is null)
            al_draw_bitmap(bmp, 0, 0, 0);

        if (_is_selected) return;
        

        Draw3DBorder(_region, SERVER_LIST_BKCOLOR);
        
        for (int i = 0 ; i <= ((_server_count - 1) / COUNT_BUTTON_PER_COLUMN); i++)
        {
            for (int j = i * COUNT_BUTTON_PER_COLUMN; (j < _server_count && j < (COUNT_BUTTON_PER_COLUMN * (i + 1))); j++)
            {
                GetSelectionRect(rc, _server_btn[j]);
                
                color = _server_btn[j].back_color;
                if (color != SERVER_BTN_BKCOLOR_NORMAL)
                    Draw3DBorder(rc, color);

                if (_server_btn[j].selected)
                    Draw3DBorder2(rc, _server_btn[j].text_color);
                
                // Write Texts
                string text = _server_btn[j].caption ~ " - " ~ std.conv.to!string(_server_btn[j].count);
                MyPen.drawText(rc, _server_btn[j].text_color, AlTransparentBlack, _server_btn[j].caption);
            }
        }
    }
    
    private void Draw3DBorder(in IntRectangle region, ALLEGRO_COLOR color)
    {
        //      const int defx = 80;
        //      const int defy = 60;
        
        al_draw_filled_rectangle(region.getLeft(), region.getTop(), region.getRight(), region.getBottom(), color);
    }

    private void Draw3DBorder2(in IntRectangle region, ALLEGRO_COLOR color)
    {
        al_draw_rectangle(region.getLeft()+1, region.getTop(), region.getRight(), region.getBottom(), color, 1.0f);
    }

    private bool parsing(int length, char[] datablock)
    {
        std.stdio.writeln("[SelectServer] Parsing length: ", length, " data: ", datablock);

        DefaultMessage msg;

        if (length < DEFBLOCKSIZE)
            return false;
        
        auto head = datablock[0 .. DEFBLOCKSIZE];
        //auto bodyy = datablock[DEFBLOCKSIZE .. length - DEFBLOCKSIZE];
        auto bodyy = datablock[DEFBLOCKSIZE .. $];
        
        DecodeMessage(msg, head);
        
        switch (msg.Ident)
        {  
            case SM_SELECTSERVER_OK:
            {
                auto str = DecodeString(bodyy.idup);
                std.stdio.writeln("str: ", str);

                string ip, sport, sidentity;
                str = GetValidStr3(str, ip, ['/']);
                sidentity = GetValidStr3(str, sport, ['/']);

                if (ip.length > 0 && sport.length > 0 && sidentity.length > 0)
                {
                    g_szServerIP = ip;
                    g_nServerPort = std.conv.to!ushort(sport);
                    g_nCertifyCode = msg.Recog; // Note: sidentity = msg.Recog

                    //m_nAnimationCounter = 0;
                    MySocket.DisconnectToServer();
                    SceneMan.ChangeScene(SceneType.SelectChr);
                }

                break;
            }

            // Connection Lost(close Connection)
            case SM_OUTOFCONNECTION:
            {
                /*m_Progress  = PRG_QUIT;                                 // Quit for Some Reason     ÇÁ·Î±×·¥ Á¾·á
                Senmsgessage(g_xMainWnd.GetSafehWnd(), WM_DESTROY, NULL, NULL);*/
                break;
            }
                
            default: break;
        }

        return false;
    }
}
